/* 
 * Quechua - the lightweight data mining framework
 *
 * Copyright (C) 2012 Marek Denis <quechua@octogan.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "iptrie.h"

int ipIndex::ipCounter = 0;

ipIndex::ipIndex(): ownmemory(false), addr(new in6_addr) {
    /*memset(addr.get(),0,sizeof((*addr.get())));*/ 
};

ipIndex::~ipIndex() {
    if(ownmemory) delete ip;
};

bool ipIndex::handle_mem(bool handle) {
    ownmemory = handle;
    return ownmemory;
}

IpNode::IpNode() {
    memset(children,0,WIDTH*sizeof(IpNode*));
};

IpNode::~IpNode() {
    for(int i=0;i<WIDTH;++i) {
       if(children[i]) delete children[i];
    }
}

IpNode* IpNode::set(const u_int8_t* label,u_int8_t len, 
         ipIndex_ptr idx_node, bool overwrite) {
    if(len) {
        int idx = *(label++);
        if(children[idx] == NULL ) {
            children[idx] = new IpNode;
        }
        return children[idx]->set(label,len-1,idx_node,false);
    } else { // the leaf
        if(false && overwrite && this->value && this->value!=idx_node )
            this->value.reset();
        this->value=idx_node;
        return this;
    }
};

IpNode* IpNode::get(const u_int8_t* label, u_int8_t len) { //const unsigned char*
    IpNode* curNode = this;
    const u_int8_t* curLabel = label; 
    int index;                         
    while(len) {
     index = *curLabel; 
     if(!curNode || !(curNode = curNode->children[index])) {
         return NULL;
     }
     len--;
     curLabel++;
    } 
    return curNode; 
}

IpTrie::IpTrie(const u_int8_t height_) : root(NULL), height(height_) {
    root = new IpNode();
    if(!root) {
        LOG(ERROR) << "IpTrie: Cannot allocate root node";
        root = NULL;
    }
};

IpTrie::~IpTrie() {
    delete root;
}

IpNode* IpTrie::getNode(const u_int8_t* label, u_int8_t len) {
    if(!root) {
        LOG(WARN) << "IpNode getNode():"
                  << " root was not initialized";
        return NULL;
    }
    return root->get(label,len);
};

IpNode* IpTrie::setNode(const u_int8_t* label, u_int8_t len,
                     ipIndex_ptr idx_node,
                     bool overwrite) 
{ 
    if(!root) {
        LOG(WARN) << "IpNode setNode():root was not initialized";
        return false;
    }
    return root->set(label,len,idx_node,overwrite);
};

